package me.firstapp.config;

import java.io.IOException;
import java.sql.SQLException;
import java.util.Properties;

import org.hibernate.SessionFactory;
import org.springframework.beans.factory.config.PropertiesFactoryBean;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportResource;
import org.springframework.core.io.ClassPathResource;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.orm.hibernate5.HibernateTemplate;
import org.springframework.orm.hibernate5.HibernateTransactionManager;
import org.springframework.orm.hibernate5.LocalSessionFactoryBean;
import org.springframework.transaction.support.TransactionTemplate;
import org.springframework.web.client.RestTemplate;

import com.alibaba.druid.pool.DruidDataSource;

import me.firstapp.api.system.ApiSignFilter;
import me.firstapp.common.utils.SpringContextTool;

@Configuration
@EnableCaching
@ImportResource("classpath:transaction.xml")
@ComponentScan(basePackages = { "me.firstapp.module", "me.firstapp.repository", "me.firstapp.service" })
public class RootConfig {

	@Bean
	public RestTemplate restTemplate() {
		return new RestTemplate();
	}

	@Bean
	public PropertiesFactoryBean configProperties() {
		PropertiesFactoryBean configProperties = new PropertiesFactoryBean();
		configProperties.setLocations(new ClassPathResource("jdbc.properties"),
				new ClassPathResource("config.properties"));
		return configProperties;
	}

	// ==============================数据源配置==================================
	@Bean
	public DruidDataSource dataSource(PropertiesFactoryBean configProperties) {
		DruidDataSource druidDataSource = new DruidDataSource();
		try {
			Properties properties = configProperties.getObject();
			// 基本属性 url、user、password
			druidDataSource.setUrl(properties.getProperty("database.jdbcUrl"));
			druidDataSource.setUsername(properties.getProperty("database.user"));
			druidDataSource.setPassword(properties.getProperty("database.password"));
			// 配置初始化大小、最小、最大
			druidDataSource.setInitialSize(Integer.valueOf(properties.getProperty("database.initialSize")));
			druidDataSource.setMinIdle(Integer.valueOf(properties.getProperty("database.minIdle")));
			druidDataSource.setMaxActive(Integer.valueOf(properties.getProperty("database.maxActive")));
			// 配置获取连接等待超时的时间
			druidDataSource.setMaxWait(Integer.valueOf(properties.getProperty("database.maxWait")));
			// 配置一个连接在池中最小生存的时间，单位是毫秒
			druidDataSource.setMinEvictableIdleTimeMillis(
					Integer.valueOf(properties.getProperty("database.minEvictableIdleTimeMillis")));
			druidDataSource.setValidationQuery(properties.getProperty("database.validationQuery"));
			druidDataSource.setTestWhileIdle(Boolean.valueOf(properties.getProperty("database.testWhileIdle")));
			druidDataSource.setTestOnBorrow(Boolean.valueOf(properties.getProperty("database.testOnBorrow")));
			druidDataSource.setTestOnReturn(Boolean.valueOf(properties.getProperty("database.testOnReturn")));

			// 打开PSCache，并且指定每个连接上PSCache的大小
			druidDataSource.setPoolPreparedStatements(
					Boolean.valueOf(properties.getProperty("database.poolPreparedStatements")));
			druidDataSource.setMaxPoolPreparedStatementPerConnectionSize(
					Integer.valueOf(properties.getProperty("database.maxPoolPreparedStatementPerConnectionSize")));

			// 配置监控统计拦截的filters
			druidDataSource.setFilters("stat");
		} catch (IOException e) {
			e.printStackTrace();
		} catch (SQLException e) {
			e.printStackTrace();
		}
		return druidDataSource;
	}

	// ============================hibernate配置=====================================
	@Bean
	public LocalSessionFactoryBean sessionFactory(DruidDataSource dataSource) {
		LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
		sessionFactory.setDataSource(dataSource);
		Properties properties = new Properties();
		properties.put("hibernate.dialect", "org.hibernate.dialect.MySQL5InnoDBDialect");
		properties.put("hibernate.show_sql", true);
		properties.put("hibernate.hbm2ddl.auto", "update");
		sessionFactory.setHibernateProperties(properties);
		sessionFactory.setPackagesToScan("me.firstapp.module", "me.firstapp.common");
		return sessionFactory;
	}

	@Bean
	public HibernateTemplate hibernateTemplate(LocalSessionFactoryBean sessionFactory) {
		HibernateTemplate hibernateTemplate = new HibernateTemplate();
		hibernateTemplate.setSessionFactory(sessionFactory.getObject());
		return hibernateTemplate;
	}

	// =================================事务配置==================================================
	@Bean
	public HibernateTransactionManager transactionManager(SessionFactory sessionFactory) {
		HibernateTransactionManager transactionManager = new HibernateTransactionManager();
		transactionManager.setSessionFactory(sessionFactory);
		return transactionManager;
	}

	@Bean
	public TransactionTemplate transactionTemplate(HibernateTransactionManager transactionManager) {
		TransactionTemplate transactionTemplate = new TransactionTemplate();
		transactionTemplate.setTransactionManager(transactionManager);
		return transactionTemplate;
	}

	// ===============================接口签名验证===============================
	@Bean
	public ApiSignFilter apiSignFilter() {
		return new ApiSignFilter();
	}

	// ==============================缓存配置========================================
	@Bean
	public RedisConnectionFactory redisCF(PropertiesFactoryBean configProperties) {
		JedisConnectionFactory cf = new JedisConnectionFactory();
		try {
			Properties properties = configProperties.getObject();
			cf.setHostName(properties.getProperty("redis.host"));
			cf.setPort(Integer.valueOf(properties.getProperty("redis.port", "6379")));
//			cf.setPassword(properties.getProperty("redis.password"));

		} catch (IOException e) {
			e.printStackTrace();
		}
		return cf;
	}

	@Bean
	public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisCF) {
		RedisTemplate<String, Object> redis = new RedisTemplate<>();
		redis.setConnectionFactory(redisCF);
		return redis;
	}

	@Bean
	public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisCF) {
		return new StringRedisTemplate(redisCF);
	}

	@Bean
	public CacheManager cacheManager(RedisTemplate<String, Object> redisTemplate) {
		return new RedisCacheManager(redisTemplate);
	}
	
	@Bean
	public SpringContextTool springContextTool() {
		return new SpringContextTool();
	}

}
